package org.nobject.common.file;

import static org.nobject.common.lang.IOUtils.getInputStreamByFilepath;

import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.io.Serializable;
import java.net.URL;
import java.util.Date;
import java.util.LinkedHashSet;
import java.util.Set;

import org.nobject.common.exception.ConvertException;
import org.nobject.common.lang.DateUtils;
import org.nobject.common.lang.IOUtils;
import org.nobject.common.lang.NumberUtils;

/**
 * 文件工具类
 * 
 * @author bianrongjun
 * @version 1.0
 */
public class FileUtils {

	/** 
	 * 读取文件到字符串
	 * @param f 文件
	 */
	public static String read2String(File f){
		try {
			return IOUtils.getString(new FileInputStream(f));
		} catch (FileNotFoundException e) {
			throw new RuntimeException(e);
		}
	}
	
	/**
	 * 读取文件到字符串
	 * @param path 路径
	 */
	public static String read2String(String path){
		return IOUtils.getString(getInputStreamByFilepath(path));
	}
	
	/** 
	 * 读取文件到字节数组
	 * @param path 路径
	 */
	public static byte[] read2Bytes(String path){
		try {
			return IOUtils.getBytes(getInputStreamByFilepath(path));
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
	}
	
	/**
	 * 读取文件<br>
	 * @param file 文件
	 */
	public static String readFile(File file) {
		try {
			return IOUtils.getString(new FileInputStream(file));
		} catch (FileNotFoundException e) {
			throw new RuntimeException(e);
		}
	}

	/******************************************************************************************************************
	 * 
	 *  makeFile 创建文件
	 * 
	 *******************************************************************************************************************/
	
	/**
	 * 创建文件
	 * @param path 路径
	 * @param content 文件内容
	 */
	public static File makeFile(String filePath,String content){
		return makeFile(filePath,content.getBytes());
	}
	
	/** 
	 * 创建文件
	 * @param path 路径
	 * @param bs 字符
	 */
	public static File makeFile(String path,byte[] bs){
		FileOutputStream os =null;
		try {
			File f;
			if(!(f=new File(new File(path).getParent())).exists()){
				f.mkdirs();
			}
			
			if ((f=new File(path)).exists()) f.delete();
			f.createNewFile();
			os = new FileOutputStream(f);
			os.write(bs);
			return f;
		} catch (IOException e) {
			throw new RuntimeException(e);
		}finally{
			if(os!=null){
				try {
					os.close();
				} catch (Exception e2) {
					throw new RuntimeException(e2);
				}
			}
		}
	}
	
	/** 
	 * 创建文件
	 * @param path 路径
	 * @param obj 对象
	 */
	public static File makeFile(String path,Serializable obj){
		return makeFile(path, SerializeUtils.toBytes(obj));
	}
	
	/******************************************************************************************************************
	 * 
	 *  getSubFilePathes 获取子文件路径
	 * 
	 *******************************************************************************************************************/
	
	
	/** 
	 * 获取子文件路径LIST
	 * @param path 路径
	 * @param withSub 带子目录
	 */
	public static Set getSubFilePathes(String path,boolean withSubDir){
		return _getSubFilePathes(path, null, withSubDir, null);
	}
	
	/** 
	 * 获取子文件路径LIST
	 * @param path 路径
	 * @param filenamePatherns 文件名匹配模式
	 * @param withSubDir 带子目录
	 * @throws IOException
	 */
	public static Set getSubFilePathes(String path,String[] filenamePatherns,boolean withSubDir) {
		return _getSubFilePathes(path, filenamePatherns, withSubDir, null);
	}	
	
	/** 
	 * 获取子文件路径LIST
	 * @param path 路径
	 * @param filenamePatherns 文件名匹配模式
	 * @param withSubDir 带子目录
	 * @param filepathes 文件路径集合
	 * @throws IOException
	 */
	private static Set _getSubFilePathes(String path,final String[] filenamePatherns,boolean withSubDir,Set filepathes) {
		if(filepathes==null) filepathes=new LinkedHashSet();
		File f=new File(path);
		if(!f.exists()) throw new RuntimeException("该路径不存在:"+path);
		if(!f.isDirectory()) throw new RuntimeException("该路径不是目录:"+path);
		String [] files=null;
		if(filenamePatherns!=null){
			files=f.list(new  FilenameFilter() {
				public boolean accept(File dir, String name) {
					if(new File(dir,name).isDirectory()) return true;
					for ( String filenamePathern:filenamePatherns) if(name.matches(filenamePathern)) return true;
					return false;
				}
			});
		}else files=f.list();
		
		for(String filename:files){
			File sf=new File(f.getPath()+File.separator+filename);
			if(sf.isDirectory()){
				if(withSubDir) filepathes.addAll(_getSubFilePathes(sf.getPath(),filenamePatherns,withSubDir,filepathes));
			}else filepathes.add(f.getPath()+File.separator+filename);
		}
		return filepathes;
	}
	
	/******************************************************************************************************************
	 * 
	 *  路径及名称 区域
	 * 
	 *******************************************************************************************************************/
	
	/** 
	 * 判断扩展名
	 * @param fileName 文件名||路径
	 * @param exts 扩展名数组
	 */
	public static boolean isExt(String fileName,String[] exts){
		for (int i = 0; i < exts.length; i++)  if(fileName.endsWith(exts[i])) return true;
		return false;
	}
	
	/**
	 * 获取文件纯名称(无扩展名)
	 * @param fileName 文件名称
	 */
	public static String getFilePureName(String fileName) {
		return _getFileNameEles(fileName, true);
	}

	/**
	 * 获取文件扩展名
	 * @param fileName 文件名称||文件全路径
	 */
	public static String getFileExtension(String fileName) {
		return _getFileNameEles(fileName, false);
	}
	
	/** 
	 * _getFileNameEles
	 * @param fileName
	 * @param simpleName
	 */
	private static String _getFileNameEles(String fileName,boolean simpleName) {
		//过滤掉 C://A.C/a.txt
		int i=Math.max(fileName.lastIndexOf("/"),fileName.lastIndexOf("\\\\"));
		i=Math.max(0, i);
		
		if(i>0){
			fileName=fileName.substring(i);
		}
		
		i = fileName.lastIndexOf(".");
		
		//如果有.分割
		if (i > 0 && i != (fileName.length() - 1)){
			if(simpleName){
				return fileName.substring(0,i);
			}else{
				return fileName.substring(i + 1);
			}
		//没有点分割	
		}else{
			if(simpleName){
				return fileName;
			}else{
				return null;
			}
		}
	}
	
	/** 
	 * 获取父路径
	 * 反斜杠会变成正斜杠
	 * @param path 路径
	 */
	public static String getParentPath(String path){
		path=formatPath(path);
		if(path.endsWith("/")){
			path = path.substring(0, path.length() - 1);
		}
		
		int p=path.lastIndexOf("/");
		if(p>=0) return  path.substring(0,p);
		return null;
	}
	
	/** 
	 * 获取文件名
	 * @param path
	 */
	public static String getFileName(String path){
		path=formatPath(path);
		if(path.endsWith("/")) return null;
		int p=path.lastIndexOf("/");
		if(p>0) return  path.substring(p+1);
		return null;
	}
	
	/** 
	 * 格式化路径
	 * @param path 路径
	 */
	public static String formatPath(String path){
		return path.replaceAll("[\\\\|/]+", "/");
	}
	
	/**
	 * 去除第一个分隔符
	 * @param path 路径
	 */
	public static String removeStartSeperator(String path) {
		while (path.startsWith("\\") || path.startsWith("/")) path = path.substring(1);
		return path;
	}

	/**
	 * 去除最后一个分隔符
	 * @param path 路径
	 */
	public static String removeEndSeperator(String path) {
		while (path.endsWith("\\") || path.endsWith("/")) path = path.substring(0, path.length() - 1);
		return path;
	}

	/**
	 * 复制文件
	 * 
	 * @param sourcePath 源地址
	 * @param destPath 目的地址
	 */
	public static void copyFile(String sourcePath, String destPath) throws IOException {
		int byteread = 0;
		InputStream in = null;
		FileOutputStream out = null;
		File f=new File(destPath);
		File dir=f.getParentFile();
		if(!dir.exists()) dir.mkdirs();
		in = new FileInputStream(sourcePath);
		out = new FileOutputStream(destPath);
		byte[] buffer = new byte[1024];
		while ((byteread = in.read(buffer)) != -1) {
			out.write(buffer, 0, byteread);
		}
		in.close();
		out.close();
	}

	/**
	 * 移动文件
	 * @param sourcePath 源地址
	 * @param destPath 目的地址
	 */
	public static void moveFile(String sourcePath, String destPath) throws IOException {
		File oldfile = new File(sourcePath);
		if (oldfile.exists()) {
			File newFile = new File(destPath);
			if(newFile.exists()) newFile.delete();
			if (!newFile.getParentFile().exists()) newFile.getParentFile().mkdirs();
			oldfile.renameTo(newFile);
		}
	}

	/** 
	 * 清空文件夹
	 * @param path 目录路径
	 * @throws IOException 删除异常
	 */
	public static void clearDir(String path) throws IOException{
		clearDir(new File(path));
	}
	
	/** 
	 * 清空文件夹
	 * @param dir 目录
	 * @throws IOException 删除异常
	 */
	public static void clearDir(File dir) throws IOException{
		if(dir.isDirectory()) FileUtils.delete(dir);
		else throw new IOException("待清理的对象不是文件夹:"+dir.getAbsolutePath());
	}
	
	/** 
	 * 删除文件
	 * @param path 路径
	 * @throws IOException 删除异常
	 * */
	public static void delete(String path) throws IOException{
		delete(new File(path));
	}
	
	/** 
	 * 删除文件
	 * @param file 文件
	 * @throws IOException 删除异常
	 */
	public static void delete(File file) throws IOException{
		if(!file.exists()) return;
		if (file.isDirectory()) {
			for(String fileName:file.list()){
				delete(new File(file.getPath()+File.separator+fileName));
			} 
			if(!file.delete()) throw new IOException("文件夹删除失败:"+file.getAbsolutePath());
		}else if(!file.delete()) throw new IOException("文件删除失败:"+file.getAbsolutePath());
	}
	
	/** 
	 * 是否以字节数组结尾
	 * @param path 路径
	 * @param bytes 字节数组
	 * @throws IOException IO异常
	 */
	public static boolean endWithBytes(String path, byte[] bytes) throws IOException{
		RandomAccessFile f=null;
		try {
			f = new RandomAccessFile(path, "r");
			if(f.length()<bytes.length) return false;
			f.seek(f.length()-bytes.length);
			byte[] cbytes=new byte[bytes.length];
			f.read(cbytes);
			boolean equals=true;
			for (int i = cbytes.length-1; i >=0 ; i--) {
				if(cbytes[i]!=bytes[i]){
					equals=false;
					continue;
				}
			}
			return equals;
		}finally{
			try {
				if(f!=null) f.close();
			} catch (Exception e) {
				throw new RuntimeException(e);
			}
		}
	}
	
	/** 
	 * 截断文件
	 * TODO 待测试
	 * @param path 路径
	 * @param end 截去的长度
	 */
	public static void cuteFile(String path,long end){
		FileOutputStream fileoutPutStream=null;
		FileInputStream inStream =null;
		try {
			File f=new File(path);
			String fileName=f.getName();
			String parentPath=f.getParentFile().getAbsolutePath();
			File tmpF=null;
			do tmpF=new File(parentPath+File.separator+fileName+System.currentTimeMillis()); while(tmpF.exists());
			tmpF.createNewFile();
			inStream = new FileInputStream(f);
			fileoutPutStream=new FileOutputStream(tmpF);
			byte[] bb = new byte[1024];
			long nl=f.length()-end;
			int len = -1;
			int c=0;
			while ((len = inStream.read(bb)) != -1){
				if(c+len>nl){
					fileoutPutStream.write(bb, 0,NumberUtils.toInt(nl-c));
					break;
				}else fileoutPutStream.write(bb, 0, len);
				c+=len;
				fileoutPutStream.flush();
			}
			fileoutPutStream.close();
			inStream.close();
			f.delete();
			tmpF.renameTo(new File(path));
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			try {
				if(fileoutPutStream!=null) fileoutPutStream.close();
				if(inStream!=null) inStream.close();
			} catch (Exception e) {
				throw new RuntimeException(e);
			}
		}
	}
	
	/** 
	 * 格式化路径
	 * @param path 路径
	 */
	public static String formatFilepath(String path){
		return new File(path).getAbsolutePath();
	}
	
	/** 
	 * 格式化URL为标准File路径，
	 * 同时对特殊字符转码，包括空格等
	 * @param url
	 */
	public static String getPath(URL url){
		return url.getFile().replaceAll("%20", " ");
//		try {
//			return URLEncoder.encode( url.getFile(), "UTF-8" );
//		} catch (UnsupportedEncodingException e) {
//			throw new RuntimeException(e);
//		}
	}
	
	public static void main(String[] args) {
		System.out.println(new File("D:\\\\SOU_HOME\\\\TOMCAT_HOME\\\\Tomcat%206.0\\\\lib").exists());
	}
}

/**
 * ExtFilenameFilter
 * 
 * @author benson
 * @date 2008-12-26
 */
class ExtFileFilter implements FileFilter {
	public static ExtFileFilter getInstance(String ext, String name, String startDate, String endDate) {
		return new ExtFileFilter(ext, name, startDate, endDate);
	}

	private String ext;
	private String name;
	private String startDate;
	private String endDate;

	ExtFileFilter(String ext, String name, String startDate, String endDate) {
		this.ext = ext;
		this.name = name;
		this.startDate = startDate;
		this.endDate = endDate;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.io.FilenameFilter#accept(java.io.File, java.lang.String)
	 */
	public boolean accept(File file) {
		if(file.isDirectory()) return true;
		String filename=file.getName();
		
		if (this.ext != null && !FileUtils.getFileExtension(filename).equalsIgnoreCase(ext)) {
			return false;
		}

		if (this.name != null && filename.indexOf(name) < 0) {
			return false;
		}

		if (this.startDate != null || this.endDate != null) {
			long fdl = file.lastModified();
			try {
				if (this.startDate != null) {
					Date d;
					
						d = DateUtils.toDate(this.startDate);
					
					long dl = d.getTime();
					if (fdl < dl) {
						return false;
					}
				}
	
				if (this.endDate != null) {
					Date d = DateUtils.toDate(this.endDate);
					long dl = d.getTime();
					if (fdl > dl) {
						return false;
					}
				}
			} catch (ConvertException e) {
				throw new  RuntimeException(e);
			}
		}

		return true;
	}
}

/**
 * DIRFilenameFilter
 * 
 * @author benson
 * @date 2008-12-26
 */
class DIRFilenameFilter implements FilenameFilter {
	private static DIRFilenameFilter filter = null;

	public static DIRFilenameFilter getInstance() {
		if (filter == null)
			filter = new DIRFilenameFilter();
		return filter;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.io.FilenameFilter#accept(java.io.File, java.lang.String)
	 */
	public boolean accept(File dir, String name) {

		File file = new File(dir, name);
		if (file.isDirectory())  return true;
		
		return false;
	}
}